package plgdb

import (
	"dgo/MyProj/PrjDBUtils"
	"dgo/MyProj/PrjHttpUtils"
	db_utils "dgo/goutils/db-utils"
	"dgo/goutils/utils"
	"dgo/plg/plgnet"
	"encoding/base64"
	"fmt"
	"gitee.com/ymofen/supervalue"
	"net/url"
	"strings"
	"time"
)

type PlgDbVarlstReader struct {
	PlgBase
	datasource   string
	selsql       string
	lastquery    string
	cache_expire time.Duration
	innerHttp    *plgnet.InnerHttp
	msglst       *utils.SyncCycleList
	kvlst        utils.GSyncMapGroup
}

func (this *PlgDbVarlstReader) ReadVar(strtype, kvsep string, enctype int) (err error, rval string) {
	dao := db_utils.NewDBHelperEx(this.datasource)
	defer dao.Close()
	sql := this.selsql
	sql = strings.ReplaceAll(sql, "$type$", strtype)

	var sb utils.BytesBuilder
	e0 := PrjDBUtils.QuerySQLRange(dao, sql, func(idx int, row []db_utils.SqlValue, err error) bool {
		key := row[0].AsString("")
		val := row[1].AsString("")
		if len(key) == 0 {
			return true
		}
		if sb.Len() > 0 {
			sb.WriteByte('\n')
		}
		if enctype == 1 {
			val = base64.RawURLEncoding.EncodeToString([]byte(val))
		} else if enctype == 2 {
			val = url.QueryEscape(val)
		} else if enctype == 3 {
			val = utils.EscapeJsonStrSimple(val)
		}
		sb.Appendf("%s%s%s", key, kvsep, val)
		return true
	})
	if e0 != nil {
		this.LogWarnMessage("sql:%s, err:%s", sql, e0.Error())
		err = e0
	} else {
		rval = sb.String()
	}
	this.lastquery = fmt.Sprintf("[%s]val:%s, sql:%s", utils.NowString(), rval, sql)
	return
}

/*
*

	{
	  "id": "varlst",
	  "type": "db.varlst.reader",
	  "conf": {
	     "api-prefix":"/varlst/",
	     "datasource":"main",
	     "sql":"select fid,fvalue from sys_vars where ftype='$type$'",
	     "cache-expire-secs":3
	  }
	}
*/
func (this *PlgDbVarlstReader) ReloadConf(conf *wrapper.SuperValue) error {
	if conf == nil {
		return nil
	}

	if this.innerHttp == nil {
		this.innerHttp = plgnet.NewInnerHttp(this)
	}
	this.innerHttp.ReloadConf(conf)
	this.innerHttp.CheckRegisterJSONApi("get", func(req *PrjHttpUtils.HttpRec) {
		strtype := req.QryAsString("type", "")
		rawflag := req.QryAsInt("rawflag", 0)
		enctype := req.QryAsInt("encode", 0)
		kvsep := req.QryAsString("kvsep", ":")
		if len(kvsep) == 0 {
			kvsep = ":"
		}
		if len(strtype) == 0 {
			if rawflag == 1 {
				req.ResponseText("err")
			} else {
				req.ResponseJSONValues("code", -1, "msg", "请指定id")
			}
			return
		} else {
			keystr := fmt.Sprintf("%s-%s-%d", strtype, kvsep, enctype)
			itm := CheckGetKvItem(&this.kvlst, keystr)
			if itm.Uptime.IsZero() || time.Since(itm.Uptime) >= this.cache_expire {
				err, val := this.ReadVar(strtype, kvsep, enctype)
				if err == nil {
					itm.Val = val
				}
				itm.Uptime = time.Now()
			}
			if rawflag == 1 {
				req.ResponseText(utils.GetStrValue(itm.Val, ""))
			} else {
				req.ResponseJSONValues("code", 0, "val", itm.Val)
			}
		}
	})

	this.cache_expire = time.Duration(conf.Int64ByName("cache-expire-secs", 3)) * time.Second

	this.datasource = conf.StringByName("datasource", "")
	this.selsql = conf.StringByName("sql", "")

	if this.msglst == nil {
		this.msglst = utils.NewSyncCycleList()
	}

	utils.DefaultPatrolTask().AddTask(this, time.Second*30, func(id interface{}, args ...interface{}) {
		//utils.DefaultWorkers().PostTaskFunc(this, this.innerWork)
	})
	return nil
}

func (this *PlgDbVarlstReader) Close() (err error) {
	this.PlgBase.Close()
	this.innerHttp.Release()
	utils.DefaultPatrolTask().DelTask(this)
	return
}

func (this *PlgDbVarlstReader) OnHttpStatus(rec *plgnet.PlgHttpRec) (rval interface{}, errcode int, err error) {
	itype := rec.QryAsInt("type", 0)
	if itype == 99 {
		json := wrapper.NewSVObject()
		json.SetKeyValue("cache-expire", utils.DurationStr(this.cache_expire))
		json.SetKeyValue("last-query", this.lastquery)
		json.SetKeyValues("now", utils.NowString())
		if rec.QryAsInt("json", 0) == 1 {
			PrjHttpUtils.ResponseAsJSON(rec.RespW, json.AsJSONStringEx(false, true))
		} else {
			PrjHttpUtils.JSON2TableRec(rec.RespW, "", json.AsJSONString(false))
		}
	} else if itype == 98 {
		rec.ResponseSyncListNEx(this.msglst)
	} else if itype == 1 {
		json := wrapper.NewSVArray()
		//searchval := rec.QryAsString("searchval", "")
		//sn := 0
		//maxn := rec.QryAsInt("n", 100)
		//this.lst.ListRangeV2(func(key, val interface{}) bool {
		//	pojo := val.(*VrsSitePojo)
		//	ok := true
		//	if len(searchval) > 0 {
		//		ok = strings.Contains(pojo.id, searchval)
		//	}
		//	return ok
		//}, func(k0, v0, k1, v1 interface{}) bool {
		//	p0 := v0.(*VrsSitePojo)
		//	p1 := v1.(*VrsSitePojo)
		//	return p0.id < p1.id
		//}, func(key, val interface{}) bool {
		//	sn++
		//	pojo := val.(*VrsSitePojo)
		//	itm := json.AppendObject()
		//	itm.SetKeyValue("sn", sn)
		//	itm.SetKeyValue("id", pojo.id)
		//	return sn < maxn
		//})

		if rec.QryAsInt("json", 0) == 1 {
			PrjHttpUtils.ResponseAsJSON(rec.RespW, json.AsJSONStringEx(false, false))
		} else {
			PrjHttpUtils.JSON2Table(rec.RespW, "", json.AsJSONString(false))
		}
	} else {
		var sb utils.BytesBuilder
		PrjHttpUtils.AppendIndexBody(&sb, "status", "status?type=99")
		PrjHttpUtils.AppendIndexBody(&sb, "msglist", "status?type=98&n=100&searchval=")
		//PrjHttpUtils.AppendIndexBody(&sb, "lst", "status?type=1&n=100&searchval=")
		PrjHttpUtils.ResponseBodyHtml(rec.RespW, sb.String())
	}
	return
}

func (this *PlgDbVarlstReader) LogInfoMessage(s string, args ...interface{}) {
	this.msglst.LogMsg(s, args...)
	utils.Log.Msgf(this.PlugId, utils.LogLV_INFO, 1, s, args...)
}

func (this *PlgDbVarlstReader) LogWarnMessage(s string, args ...interface{}) {
	this.msglst.LogMsg(s, args...)
	utils.Log.Msgf(this.PlugId, utils.LogLV_WARN, 1, s, args...)
}

func CreatePlgDbVarlstReaderFunc(args ...interface{}) (rval interface{}, err error) {
	obj := &PlgDbVarlstReader{}

	if len(args) > 0 {
		if str, ok := args[0].(string); ok {
			obj.PlugId = str
		}
	}
	rval = obj
	return
}
